package com.ruoyi.project.business.domain.ruleengine;

import com.alibaba.fastjson.JSON;
import com.ruoyi.project.business.domain.entity.DailyScheduleEmp;
import com.ruoyi.project.business.domain.exceptions.RuleException;
import com.ruoyi.project.business.domain.model.JudgeResult;
import com.ruoyi.project.business.domain.model.daily.DailyScheduleSolution;
import com.ruoyi.project.business.domain.model.daily.TimePeriodMirror;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 普通的排班引擎(日排班)
 */
@Slf4j
public class CommonDailyScheduleAssignEngine {
    @Setter
    private List<DailyScheduleEmp> emps;
    @Setter
    private List<TimePeriodMirror> timePeriods;
    @Setter
    private Integer assignMode = 1; // 0: 把人往班上排 1: 把班往人上排


    private DailyScheduleSolution solution = new DailyScheduleSolution();;

    public DailyScheduleSolution tryAssign() {
        if (CollectionUtils.isEmpty(emps)) {
            throw new RuleException("错误的排班目标");
        }

        ArrayList<DailyScheduleEmp> empsCopy = new ArrayList<>(emps);
        Map<Long, List<TimePeriodMirror>> userShiftMap = initUserShifts(empsCopy);

        if(CollectionUtils.isNotEmpty(timePeriods)) {
            if(assignMode == 1) {
                modelOne(empsCopy, userShiftMap);
            } else if(assignMode == 1) {
                modelZero(empsCopy, userShiftMap);
            }

        }

        // 普通的排班
        return solution;
    }

    /**
     * 班往人上排  人排满了就不管了
     * @param empsCopy
     * @param userShiftMap
     */
    private void modelOne(ArrayList<DailyScheduleEmp> empsCopy, Map<Long, List<TimePeriodMirror>> userShiftMap) {
        for (DailyScheduleEmp emp : empsCopy) {
            for (Iterator<TimePeriodMirror> timePeriodIterator = timePeriods.iterator(); timePeriodIterator.hasNext();) {
                TimePeriodMirror timePeriod = timePeriodIterator.next();
                emp.setTryAssignTimePeriod(timePeriod);
                JudgeResult result = emp.ifAssign(solution);
                if (result.isAccept()) {
                    log.info("user {} 能匹配 timePeriod {} ", JSON.toJSONString(timePeriod), emp.getUserId());
                    userShiftMap.get(emp.getUserId()).add(result.getTimePeriod());
                    // 已匹配上的班，移除
                    timePeriodIterator.remove();
                } else {
                    log.info("不能匹配， 因为：{}", result.getTips());
                    if(result.isStopTask()) {
                        break;
                    }
                }
            }
        }
    }

    /**
     * 人往班上排： 班都排好就不管了
     * @param empsCopy
     * @param userShiftMap
     */
    private void modelZero(ArrayList<DailyScheduleEmp> empsCopy, Map<Long, List<TimePeriodMirror>> userShiftMap) {
        for (Iterator<TimePeriodMirror> timePeriodIterator = timePeriods.iterator(); timePeriodIterator.hasNext();) {
            TimePeriodMirror timePeriod = timePeriodIterator.next();
            for (DailyScheduleEmp emp : empsCopy) {
                emp.setTryAssignTimePeriod(timePeriod);
                JudgeResult result = emp.ifAssign(solution);
                if (result.isAccept()) {
                    log.info("user {} 能匹配 timePeriod {} ", JSON.toJSONString(result.getTimePeriod()), emp.getUserId());
                    userShiftMap.get(emp.getUserId()).add(result.getTimePeriod());
                    // 已匹配上的班，移除
                    timePeriodIterator.remove();
                } else {
                    log.error("不能匹配， 因为：{}", result.getTips());
                    if(result.isStopTask()) {
                        break;
                    }
                }

            }
        }
    }

    private Map<Long, List<TimePeriodMirror>> initUserShifts(ArrayList<DailyScheduleEmp> empsCopy) {
        Map<Long, List<TimePeriodMirror>> userShifts = solution.getUserShifts();

        for (DailyScheduleEmp emp : empsCopy) {
            userShifts.put(emp.getUserId(), new ArrayList<>());
        }
        return userShifts;
    }

}
